Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSON-RPC capability #1373

Merged
merged 2 commits into from
Jan 20, 2025
Merged

Conversation

kannibalox
Copy link
Contributor

Based off the work in https://github.com/jesec/rtorrent, this implements the 2.0 specification: https://www.jsonrpc.org/specification. It adds a new RpcManager class and a little SCGI logic to handle switching between XML and JSON seamlessly. If the CONTENT_TYPE header is present and set to application/json (or text/xml for XML-RPC), it'll use that, otherwise it will peek at the body to auto-detect it.

The main benefit is reduced message size, as seen on this synthetic set of 10k torrents:

$ rtxmlrpc -U scgi://localhost:8888?rpc=xml d.multicall2 '' main d.name= d.hash= d.size_bytes= --debug |& grep stats
DEBUG:pyrosimple.scripts.rtxmlrpc.RtorrentXmlRpc:RPC stats: 1 requests (387 bytes) in 0.029s (response 1.9 MiB)

$ rtxmlrpc -U scgi://localhost:8888?rpc=json d.multicall2 '' main d.name= d.hash= d.size_bytes= --debug |& grep stats
DEBUG:pyrosimple.scripts.rtxmlrpc.RtorrentXmlRpc:RPC stats: 1 requests (106 bytes) in 0.024s (response 710.9 KiB)

One limitation of JSON-RPC is that it doesn't have a dedicated binary data type. Due to that, base64 data URI support has been added to all the load.* commands. Those are currently the only commands which normally need to take binary data, but any future commands would have to follow the same pattern or implement their own scheme.

Note for Flood users When Flood detects the presence of JSON-RPC, it assumes that the full jesec/rtorrent capabilities are available, which breaks a couple things. Thankfully, it's pretty easy to provide some stubs/redirects to get it working:
method.redirect=load.throw,load.normal
method.redirect=load.start_throw,load.start
method.insert=d.down.sequential,value|const,0
method.insert=d.down.sequential.set,value|const,0

src/command_network.cc Outdated Show resolved Hide resolved
src/core/manager.cc Outdated Show resolved Hide resolved
@rakshasa
Copy link
Owner

This should probably add options to enable/disable xmlrpc or json handling.

@kannibalox
Copy link
Contributor Author

This should probably add options to enable/disable xmlrpc or json handling.

Were you thinking compile flag options or command options, and can you expand on the use case for this? They should be able to coexist peacefully, if a client doesn't want to use one or the other all they have to do is not send that type of request.

@rakshasa
Copy link
Owner

One example is the flood users, who knows where else this might cause issues.

This allows users/providers force the use of a particular protocol for performance or compatibility reasons.

It should be command value to enable/disable each.

@kannibalox
Copy link
Contributor Author

Added a toggle for each, and renamed some of the commands/variables from xmlrpc to rpc

src/command_network.cc Outdated Show resolved Hide resolved
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Clang-Tidy found issue(s) with the introduced code (1/1)

test/rpc/jsonrpc_test.h Show resolved Hide resolved
test/rpc/jsonrpc_test.h Show resolved Hide resolved
test/rpc/jsonrpc_test.h Show resolved Hide resolved
test/rpc/jsonrpc_test.h Show resolved Hide resolved
test/rpc/jsonrpc_test.h Show resolved Hide resolved
bool process(RPCType type, const char* in_buffer, uint32_t length, slot_response_callback callback);

void insert_command(const char* name, const char* parm, const char* doc);
static void object_to_target(const torrent::Object& obj, int callFlags, rpc::target_type* target);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ readability-identifier-naming ⚠️
invalid case style for parameter callFlags

Suggested change
static void object_to_target(const torrent::Object& obj, int callFlags, rpc::target_type* target);
static void object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* target);

test/rpc/jsonrpc_test.h Show resolved Hide resolved
src/thread_worker.h Show resolved Hide resolved
kannibalox and others added 2 commits January 20, 2025 00:55
Inline nlohmann/json for the JSON parsing itself, and handle requests
with the same SCGI interface as XML-RPC.

Based off the work in https://github.com/jesec/rtorrent
@rakshasa rakshasa merged commit 787e23a into rakshasa:master Jan 20, 2025
2 checks passed
@trim21
Copy link
Contributor

trim21 commented Jan 21, 2025

really glad to see this feature is finally implemented on upstream

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants